#include <algorithm>
#include <iostream>
#include "Master.h"
#include "TwoWayList.cc"

using namespace std;

MasterImp::MasterImp(void)
#ifdef DEBUG_EVPROC
: EventProcessorImp(true,"Master") // comment to remove debug
#endif
{
  
  // register the message function
  RegisterMessageProcessor(DieMessage::type, &Die, 0 /* priority */);

  RegisterMessageProcessor(GenDoneMessage::type, &GenDone, 1 /* priority */);
  
  RegisterMessageProcessor(WorkerDoneMessage::type, &WorkerDone, 2 /* priority */);
  RegisterMessageProcessor(ReadyMessage::type, &WorkerReady, 3 /* priority */);
  
  RegisterMessageProcessor(FillMessage::type, &PushNumber, 4 /* priority */);
  
  RegisterMessageProcessor(DoneMessage::type, &SumDone, 5 /* priority */);

  sum = 0;
	
  generatorsDone = false;

  current = 0;

}

void MasterImp::PutIntoPending(){
	vector<int>::iterator xit;
	for(xit = buffer.end()-1;xit != buffer.end() - 11;--xit){
		pending.push_back(*xit);
	}	
}

//Handling the fill message from the Generator

MESSAGE_HANDLER_DEFINITION_BEGIN(MasterImp, PushNumber, FillMessage)
	
	//cout<<"Got the fill Message - Master "<<msg.number<<endl;	

	evProc.buffer.push_back(msg.number);
	
	int bufferSize = (int)evProc.buffer.size();
	// Here we send the vector if 10 elements are added to the vector
	if(bufferSize%10 == 0 ){

		evProc.myWorkers.MoveToStart();
		EventProcessor currentWorker;
		// Checking if i have available workers
		// if yes then assign them work
		if(evProc.myWorkers.Length() != 0){
			evProc.myWorkers.Remove(currentWorker);
			EventProcessor myInterfClone;
			myInterfClone.CopyFrom(evProc.myInterface);
			AddMessage_Factory(currentWorker, evProc.current,evProc.buffer,myInterfClone);
		}
		// No worker free to take up the job so put in pending jobs
		else{
			evProc.PutIntoPending();
		}
			evProc.current += 10;
	}
	
	EventProcessor myInterfClone;
	myInterfClone.CopyFrom(evProc.myInterface);

	NextNumberMessage_Factory(msg.sender,0,myInterfClone);

MESSAGE_HANDLER_DEFINITION_END


void MasterImp::SendPending(EventProcessor& sender){
	vector<int> sendThis;
	vector<int>::iterator xit;
	for(xit = pending.begin();xit != pending.begin()+10;++xit){
		sendThis.push_back(*xit);
	}	
	pending.erase(pending.begin(),pending.begin()+10);
	
	EventProcessor myInterfClone;
	myInterfClone.CopyFrom(myInterface);
	AddMessage_Factory(sender, 0, sendThis,myInterfClone);
}

//Handling the message sent by worker signalling sum is done

MESSAGE_HANDLER_DEFINITION_BEGIN(MasterImp, SumDone, DoneMessage)
	
	evProc.sum += msg.sum;
	if(evProc.pending.size() == 0){

		if(!evProc.generatorsDone){
			evProc.myWorkers.Append(msg.sender);
		}

		else{
			KillEvProc(msg.sender);
		}
	}
// if there is pending work then send to the worker
else{
	evProc.SendPending(msg.sender);
}

MESSAGE_HANDLER_DEFINITION_END

// This message indicates that all the generators are done
// kill free workers.
MESSAGE_HANDLER_DEFINITION_BEGIN(MasterImp, GenDone, GenDoneMessage)
		
	evProc.generatorsDone = true;
	cout<<"Got GenDone Message - Master"<<endl;
	evProc.myWorkers.MoveToStart();
	while(evProc.myWorkers.Length() != 0)
	{
		cout<<" Killing the workers "<<evProc.myWorkers.Length()<<endl;
		EventProcessor newWorker;
		evProc.myWorkers.Remove(newWorker);
		KillEvProc(newWorker);
		evProc.myWorkers.MoveToStart();


	}

MESSAGE_HANDLER_DEFINITION_END

//Workers are ready to do the sum, append them to the myWorkers list 

MESSAGE_HANDLER_DEFINITION_BEGIN(MasterImp, WorkerReady, ReadyMessage)
	
	evProc.myWorkers.Append(msg.sender);

	cout<<"Worker Ready - Master "<<evProc.myWorkers.Length()<<endl;

MESSAGE_HANDLER_DEFINITION_END

MESSAGE_HANDLER_DEFINITION_BEGIN(MasterImp, WorkerDone, WorkerDoneMessage)
		
		cout<<"All the workers Done !!! "<<endl;
		evProc.Seppuku();
	
MESSAGE_HANDLER_DEFINITION_END


MESSAGE_HANDLER_DEFINITION_BEGIN(MasterImp, Die, DieMessage)

	cout<<"The sum is "<<evProc.sum<<endl;
	evProc.EventProcessorImp::processDieMessage(evProc,msg);

MESSAGE_HANDLER_DEFINITION_END

